<?php

declare(strict_types=1);

namespace app\sys\controller;

use app\sys\service\fileService;
use app\sys\service\syncService;
use PhpOffice\PhpSpreadsheet\IOFactory;
use PhpOffice\PhpSpreadsheet\Reader\Exception;
use think\admin\Controller;
use think\admin\model\SysWorldCode;
use think\admin\service\AdminService;
use think\admin\Storage;
use think\db\exception\DataNotFoundException;
use think\db\exception\DbException;
use think\db\exception\ModelNotFoundException;
use think\exception\HttpResponseException;
use think\file\UploadedFile;


/**
 * 原产国（地区）管理
 * class WorldCode
 * @package app\sys\controller
 */
class WorldCode extends Controller
{
    /**
     * 原产国（地区）分页列表
     * @auth true
     * @return void
     * @throws DataNotFoundException
     * @throws DbException
     * @throws ModelNotFoundException
     */
    public function page()
    {
        $query = SysWorldCode::mQuery();
        $query->where(['is_deleted' => 0]);
        // 数据列表搜索过滤
        $query->equal('status,digit_code,two_char_code,three_char_code')->dateBetween('create_time');
        $query->like('full_name,cn_abbreviation,en_abbreviation');
        $query->dataScope('created_by');
        $lists = $query->order('sort asc,id asc')->page();
    }

    /**
     * 原产国（地区）列表
     * @login true
     * @return void
     * @throws DataNotFoundException
     * @throws DbException
     * @throws ModelNotFoundException
     */
    public function list()
    {
        $lists = SysWorldCode::mk()
            ->where(['is_deleted' => 0, 'status' => 0])
            ->order('id DESC')
            ->select()
            ->toArray();
        $this->success('数据获取成功', $lists);
    }

    /**
     * 获取一条单页详情
     * @auth true
     * @return void
     */
    public function detail()
    {
        sysoplog('原产国（地区）管理', '原产国（地区）详情获取成功');
        $this->success('操作成功', SysWorldCode::detail($this->request->param('id')));
    }

    /**
     * 添加原产国（地区）
     * @auth true
     * @return void
     */
    public function add()
    {
        sysoplog('原产国（地区）管理', '新增原产国（地区）');
        SysWorldCode::mForm('form');
    }

    /**
     * 编辑原产国（地区）
     * @auth true
     * @return void
     */
    public function edit()
    {
        sysoplog('原产国（地区）管理', '编辑原产国（地区）');
        SysWorldCode::mForm('form');
    }

    /**
     * 同步原产国（地区）
     * @auth true
     * @return void
     */
    public function sync()
    {
        try {
            $result = syncService::syncData('sync/world');
            if (empty($result['code'])) $this->error($result['info']);
            set_time_limit(100);
            foreach ($result['data'] as $vo) SysWorldCode::mUpdate(['world_code_id' => $vo['world_code_id'], 'cn_abbreviation' => $vo['cn_abbreviation'], 'en_abbreviation' => $vo['en_abbreviation'], 'two_char_code' => $vo['two_char_code'], 'three_char_code' => $vo['three_char_code'], 'digit_code' => $vo['digit_code'], 'full_name' => $vo['full_name'], 'is_deleted' => 0], 'world_code_id');
            $this->success('同步原产国（地区）成功！');
        } catch (HttpResponseException $exception) {
            throw $exception;
        } catch (\Exception $exception) {
            $this->error('同步原产国（地区）数据失败！');
        }
    }

    /**
     * 修改状态
     * @auth true
     * @return void
     */
    public function state()
    {
        sysoplog('原产国（地区）管理', '修改原产国（地区）状态');
        SysWorldCode::mSave($this->_vali([
            'status.in:0,1' => '状态值范围异常！',
            'status.require' => '状态值不能为空！',
        ]));
    }

    /**
     * 删除原产国（地区）
     * @auth true
     * @return void
     */
    public function delete()
    {
        sysoplog('原产国（地区）管理', '原产国（地区）删除成功');
        SysWorldCode::mSave(['is_deleted' => 1]);
    }

    /**
     * 批量上传
     * @return void
     */
    public function importData()
    {
        [$uuid, $unid, $unexts] = $this->initUnid();
        // 开始处理文件上传
        $file = $this->getFile();
        $extension = strtolower($file->getOriginalExtension());
        $saveFileName = input('key') ?: Storage::name($file->getPathname(), $extension, '', 'md5_file');
        $size = $file->getSize();
        [$state, $msg] = fileService::performFileSecurityCheck($saveFileName, $extension, $uuid, $unid, $unexts);
        if (!$state) $this->error($msg);
        try {
            $info = fileService::moveUploadedFile($file, $saveFileName);
            if (isset($info['url'])) {
                if (in_array($extension, ['xls', 'xlsx'])) {
                    $importData = $this->readExcelData('../safefile/' . $saveFileName, $extension);
                    $this->insertDataIntoDatabase($importData);
                } else {
                    $this->error('仅限上传xls、xlsx文件，具体请参考模板');
                }
            } else {
                $this->error('文件处理失败，请稍候再试！');
            }
        } catch (HttpResponseException $exception) {
            throw $exception;
        } catch (\Exception $exception) {
            trace_file($exception);
            $this->error($exception->getMessage());
        }
    }

    /**
     * 初始化用户状态
     * @param boolean $check
     * @return array
     */
    private function initUnid(bool $check = true): array
    {
        $uuid = AdminService::getUserId();
        [$unid, $exts] = AdminService::withUploadUnid();
        if ($check && empty($uuid) && empty($unid)) {
            $this->error('未登录，禁止使用文件上传！');
        } else {
            return [$uuid, $unid, $exts];
        }
    }

    /**
     * 获取文件对象
     * @return UploadedFile|void
     */
    private function getFile(): UploadedFile
    {
        try {
            $file = $this->request->file('file');
            if ($file instanceof UploadedFile) {
                return $file;
            } else {
                $this->error('未获取到上传的文件对象！');
            }
        } catch (HttpResponseException $exception) {
            throw $exception;
        } catch (\Exception $exception) {
            trace_file($exception);
            $this->error(lang($exception->getMessage()));
        }
    }

    /**
     * 读取Excel处理数据
     * @param $filePath
     * @param $extension
     * @return array
     * @throws \PhpOffice\PhpSpreadsheet\Exception
     * @throws Exception
     */
    private function readExcelData($filePath, $extension)
    {
        if ($extension == 'xlsx') {
            $objReader = IOFactory::createReader('Xlsx');
        } else {
            $objReader = IOFactory::createReader('Xls');
        }
        $objReader->setReadDataOnly(TRUE);
        $objPHPExcel = $objReader->load($filePath);
        $sheet = $objPHPExcel->getSheet(0);
        $highestRow = $sheet->getHighestRow();
        $importData = [];
        for ($j = 3; $j <= $highestRow; $j++) {
            $rowData = [
                'cn_abbreviation' => trim((string)$objPHPExcel->getActiveSheet()->getCell("B" . $j)->getValue()),
                'en_abbreviation' => trim((string)$objPHPExcel->getActiveSheet()->getCell("C" . $j)->getValue()),
                'two_char_code' => trim((string)$objPHPExcel->getActiveSheet()->getCell("D" . $j)->getValue()),
                'three_char_code' => trim((string)$objPHPExcel->getActiveSheet()->getCell("E" . $j)->getValue()),
                'digit_code' => trim((string)$objPHPExcel->getActiveSheet()->getCell("F" . $j)->getValue()),
                'full_name' => trim((string)$objPHPExcel->getActiveSheet()->getCell("G" . $j)->getValue()),
            ];
            $importData[] = $rowData;
        }
        return $importData;
    }

    /**
     * 写入数据
     * @param $importData
     * @return void
     */
    private function insertDataIntoDatabase($importData)
    {
        $num = 1000; // 每次导入条数
        $limit = ceil(count($importData) / $num);
        $j = 0;
        for ($i = 1; $i <= $limit; $i++) {
            $offset = ($i - 1) * $num;
            $dataCode = array_slice($importData, $offset, $num);
            $result = SysWorldCode::mk()->insertAll($dataCode);
            $j++;
        }
        if ($j === (int)$limit) {
            $this->success('提交成功');
        }
    }
}
